package org.nehc.algorithm.redissonutils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;

import java.time.Duration;

/**
 * Redisson 原子操作工具类
 * 提供原子值的增减、设置等操作
 *
 * @author system
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RedissonAtomicUtils {

    private static final RedissonClient CLIENT = RedissonUtils.getClient();

    /**
     * 设置原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param value     值
     */
    public static void setAtomicValue(final String cacheName, final String key, long value) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        atomic.set(value);
        atomic.expire(Duration.ofDays(1));
    }

    /**
     * 设置原子值及过期时间
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param value     值
     * @param duration  过期时间
     */
    public static void setAtomicValue(final String cacheName, final String key, long value, Duration duration) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        atomic.set(value);
        atomic.expire(duration);
    }

    /**
     * 获取原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 当前值
     */
    public static long getAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.get();
    }

    /**
     * 递增原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 递增后的值
     */
    public static long incrAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.incrementAndGet();
    }

    /**
     * 递增原子值（指定增量）
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param delta     增量
     * @return 递增后的值
     */
    public static long incrAtomicValue(final String cacheName, final String key, long delta) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.addAndGet(delta);
    }

    /**
     * 递减原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 递减后的值
     */
    public static long decrAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.decrementAndGet();
    }

    /**
     * 递减原子值（指定减量）
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param delta     减量
     * @return 递减后的值
     */
    public static long decrAtomicValue(final String cacheName, final String key, long delta) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.addAndGet(-delta);
    }

    /**
     * 比较并设置原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param expect    期望值
     * @param update    更新值
     * @return true=设置成功；false=设置失败
     */
    public static boolean compareAndSetAtomicValue(final String cacheName, final String key, long expect, long update) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.compareAndSet(expect, update);
    }

    /**
     * 获取并设置原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param newValue  新值
     * @return 设置前的值
     */
    public static long getAndSetAtomicValue(final String cacheName, final String key, long newValue) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.getAndSet(newValue);
    }

    /**
     * 获取并递增原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 递增前的值
     */
    public static long getAndIncrAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.getAndIncrement();
    }

    /**
     * 获取并递减原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 递减前的值
     */
    public static long getAndDecrAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.getAndDecrement();
    }

    /**
     * 获取并增加原子值（指定增量）
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param delta     增量
     * @return 增加前的值
     */
    public static long getAndAddAtomicValue(final String cacheName, final String key, long delta) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.getAndAdd(delta);
    }

    /**
     * 删除原子值
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return true=删除成功；false=删除失败
     */
    public static boolean deleteAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.delete();
    }

    /**
     * 检查原子值是否存在
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return true=存在；false=不存在
     */
    public static boolean isExistsAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.isExists();
    }

    /**
     * 设置原子值的过期时间
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @param duration  过期时间
     * @return true=设置成功；false=设置失败
     */
    public static boolean expireAtomicValue(final String cacheName, final String key, Duration duration) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.expire(duration);
    }

    /**
     * 获取原子值的剩余生存时间
     *
     * @param cacheName 缓存名称
     * @param key       Redis键
     * @return 剩余生存时间（毫秒），-1表示永久，-2表示不存在
     */
    public static long remainTimeToLiveAtomicValue(final String cacheName, final String key) {
        RAtomicLong atomic = CLIENT.getAtomicLong(RedissonUtils.getKey(cacheName, key));
        return atomic.remainTimeToLive();
    }
}